/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 *
 * $Id: EmergencyStopData.cpp,v 1.2 2009-11-06 11:45:21 morsko Exp $
 *
 * \file
 * \brief Implementatino for EmergencyStop data encoder/decoder
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 */
#include "EmergencyStopData.hpp"
#include "binbag.h"
#include <stdio.h>
#include "owndebug.h"

//*****************************************************************************
//*****************************************************************************
using namespace MaCI::EmergencyStop;
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************

CEmergencyStopData::CEmergencyStopData()
  : iTimestampPtr(NULL),
    iCommandPtr(NULL),
    iStatusPtr(NULL),
    iTimeoutTimePtr(NULL)
{
}
//*****************************************************************************

CEmergencyStopData::~CEmergencyStopData()
{
}
//*****************************************************************************

CEmergencyStopData::CEmergencyStopData(const CEmergencyStopData &aData)
  : iTimestampPtr(NULL),
    iCommandPtr(NULL),
    iStatusPtr(NULL),
    iTimeoutTimePtr(NULL)
{
  // Call assignment operator.
  *this = aData;
}
//*****************************************************************************

CEmergencyStopData &CEmergencyStopData::operator=(const CEmergencyStopData &aData)
{
  // Reset
  Reset();

  // Create an internal BinBag instance
  if (CreateInternalBinBag(aData.iBinBagContainer) == false) {
    dPrint(4,"WARNING: Failed to create internal binbag for object %p from object %p",
           this, &aData);
  }
  
  // Do the decode on the buffer; it sets pointers and
  if (DecodeFrom() == false) {
    dPrint(4,"Warning: Failed to Decode CEmergencyStopData even though assignment operator used?");
  }
  
  return *this; 
}
//*****************************************************************************

bool CEmergencyStopData::DecodeFrom(gim::binbag::CBinBag *aBinBag)
{
  bool result = true;
  const gim::binbag::TBinBlob *b = NULL;
  int previous_type = -1;
  
  // Store pointer and test it for NullNess
  if (aBinBag != NULL)  
    iBinBagContainer = aBinBag;
  
  // Parse
  if (iBinBagContainer && iBinBagContainer->Rewind()) {
    while( (b = iBinBagContainer->GetNextBinary()) && result ) {
      switch(b->type) {
      case KTypeTimestamp:
	if (iTimestampPtr == NULL) {
	  iTimestampPtr = reinterpret_cast<const Common::TTimestamp *>(b->data);
	} else { 
          dPrint(10,"Decoding Error: iTimestampPtr was not NULL");
          result = false; 
        }
	break;

      case KTypeCommand:
        if (iCommandPtr == NULL) {
          iCommandPtr = reinterpret_cast<const TCommand *>(b->data);
        } else { 
          dPrint(10,"Decoding Error: iCommandPtr was not NULL");
          result = false; 
        }
        break;

      case KTypeEmergencyStopStatus:
        if (iStatusPtr == NULL) {
          iStatusPtr = reinterpret_cast<const TStatus *>(b->data);
        } else { 
          dPrint(10,"Decoding Error: iStatusPtr was not NULL");
          result = false; 
        }
        break;
        
      case KTypeTimeoutTime:
        if (iTimeoutTimePtr == NULL) {
          iTimeoutTimePtr = reinterpret_cast<const TTimeoutTime *>(b->data);
        } else { 
          dPrint(10,"Decoding Error: iTimeoutTimePtr was not NULL");
          result = false; 
        }
        break;
      default:
	// Unknown Type in BinBag. Do nothing.
	break;
      }
      
      // Store previous type
      previous_type = b->type;
    }
  } else {
    result = false;
  }
  
  // Store the result
  SetReadOnlyContainer(result);
  
  return result;
}
//*****************************************************************************

void CEmergencyStopData::Reset()
{ 
  CMaCIData::Reset();

  iTimestampPtr = NULL;
  iCommandPtr = NULL;
  iStatusPtr = NULL;
  iTimeoutTimePtr = NULL;
}
//*****************************************************************************

bool CEmergencyStopData::SetTimestamp(const Common::TTimestamp &aStamp)
{
  bool result = false;
  if (!IsReadOnlyContainer() && iTimestampPtr == NULL) {
    const gim::binbag::TBinBlob *b = 
      iBinBagContainer->AddBinary(KTypeTimestamp, 
                                  (const char *)&aStamp, 
                                  sizeof(Common::TTimestamp));
    iTimestampPtr = reinterpret_cast<const Common::TTimestamp *>(b->data);

    // Mark last element
    SetLastElementType(KTypeTimestamp);

    result = true;
  }
  return result;
}
//*****************************************************************************

bool CEmergencyStopData::SetCommand(const TCommand &aCommand)
{
  bool result = false;
  if (!IsReadOnlyContainer() && iCommandPtr == NULL) {
    // Use the handy Macro found from MaCIData
    ADDELEMENT(TCommand, KTypeCommand, iCommandPtr, aCommand);
    result = true;
  }
  return result;
}
//*****************************************************************************
bool CEmergencyStopData::SetEmergencyStopStatus(const TStatus &aStatus)
{
  bool result = false;
  if (!IsReadOnlyContainer() && iStatusPtr == NULL) {
    // Use the handy Macro found from MaCIData
    ADDELEMENT(TStatus, KTypeEmergencyStopStatus, iStatusPtr, aStatus);
    result = true;
  }
  return result;
}
//*****************************************************************************

bool  CEmergencyStopData::SetTimeoutTime(const TTimeoutTime &aTimeoutTime)
{
  bool result = false;
  if (!IsReadOnlyContainer() && iTimeoutTimePtr == NULL) {
    // Use the handy Macro found from MaCIData
    ADDELEMENT(TTimeoutTime, KTypeTimeoutTime , iTimeoutTimePtr, aTimeoutTime);
    result = true;
  }
  return result;
}
//*****************************************************************************

void CEmergencyStopData::Print(const int l) const
{
 
  const gim::binbag::TBinBlob *b = NULL;
  // Parse
  if (iBinBagContainer && iBinBagContainer->Rewind()) {
    while( (b = iBinBagContainer->GetNextBinary())) {
      switch(b->type) {
      case KTypeTimestamp: {
	const Common::TTimestamp *ts = 
          reinterpret_cast<const Common::TTimestamp *>(b->data);
	dPrint(l,"Common::TTimestamp : %d, %d", 
	       ts->timestamp_s,
	       ts->timestamp_us);
	break;
      }

      case KTypeCommand: {
        const TCommand *cp = reinterpret_cast<const TCommand *>(b->data);
        dPrint(l,"TCommand: %d",
               cp->cmd);
        break;
      }
	
      case KTypeEmergencyStopStatus: {
        const TStatus *s = reinterpret_cast<const TStatus *>(b->data);
        dPrint(l,"TStatus: status %d",
               s->emergencyStopStatus);
        break;
      }

      case KTypeTimeoutTime: {
        const TTimeoutTime *to = reinterpret_cast<const TTimeoutTime *>(b->data);
        dPrint(l,"TTimeoutTime: time %u",
               to->timeoutTime_ms);
        break;
      }
      default:
	// Unknown Type in BinBag. Do nothing.
	break;
      }
    }
  }
}
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************

#ifdef COMPILE_EMERGENCYSTOPDATA_STANDALONE_MAIN
using namespace MaCI::EmergencyStop;

int main(void)
{
  gim::binbag::CBinBag bb;
  CEmergencyStopData A;
  CEmergencyStopData B;
  unsigned int timeoutTime = 2000;

  printf("Carry out Encoding/Decoding test.\n");

  printf("Encoding...\n");
  // Do Encoding 
  A.EncodeTo(&bb);
  printf("Encode: Timestamp(1,2)...");
  A.SetTimestamp(MaCI::Common::TTimestamp(1, 2));
  printf("OK.\n");

  printf("Encode: TCommand(KCommandActivateEmergencyStop) (%d)...",KCommandActivateEmergencyStop);
  A.SetCommand(TCommand( KCommandActivateEmergencyStop));
  printf("OK.\n");

  printf("Encode: TStatus(KStatusEmergencyStopActivated) (%d)...",KStatusEmergencyStopActivated);
  A.SetEmergencyStopStatus(TStatus(KStatusEmergencyStopActivated));
  printf("OK.\n");

  printf("Encode: TTimeoutTime(%u)...",timeoutTime);
  A.SetTimeoutTime(TTimeoutTime(timeoutTime));
  printf("OK.\n");

  printf("\nDecoding...\n");
  // Do Decoding
  B.DecodeFrom(&bb);
  printf("Decode: Timestamp = (%d, %d)\n", 
	 B.GetTimestamp()->timestamp_s, 
	 B.GetTimestamp()->timestamp_us);
  
 printf("Decode: TCommand = (%d)\n", 
	 B.GetCommand()->cmd);
  assert(B.GetCommand()->cmd == KCommandActivateEmergencyStop);

  printf("Decode: TStatus = (%d)\n", 
        B.GetStatus()->emergencyStopStatus);
  assert(B.GetStatus()->emergencyStopStatus == KStatusEmergencyStopActivated);

  printf("Decode: TTimeoutTime = (%d)\n", 
        B.GetTimeoutTime()->timeoutTime_ms);
  assert( B.GetTimeoutTime()->timeoutTime_ms == timeoutTime);

  printf("\nTest complete.\n");
  

}
#endif
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
